package com.example.springsecurity.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.example.springsecurity.common.config.RedisCache;
import com.example.springsecurity.common.config.SystemUserLoginDetail;
import com.example.springsecurity.common.constant.Constant;
import com.example.springsecurity.common.enums.GlobalExceptionEnum;
import com.example.springsecurity.common.exception.BizException;
import com.example.springsecurity.common.utils.JwtTokenUtil;
import com.example.springsecurity.entity.SystemUser;
import com.example.springsecurity.mapper.SystemUserMapper;
import com.example.springsecurity.service.SystemLoginService;
import com.example.springsecurity.common.vo.UserLoginResultVo;
import com.example.springsecurity.common.vo.login.SystemUserLoginInfoVo;
import jakarta.annotation.Resource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

import static com.example.springsecurity.common.constant.Constant.REDIS_LOGIN_PATH;
import static com.example.springsecurity.common.utils.LoginInfoUtil.deleteUserLoginInfo;

/**
 * @Description：系统登陆服务接口实现
 * @Author： fengcheng
 * @Date： 2024/12/19 10:17
 */
@Slf4j
@Data
@Service
public class SystemLoginServiceImpl implements SystemLoginService {

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private RedisCache redisCache;

    @Resource
    private SystemUserMapper systemUserMapper;

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private AuthenticationManager authenticationManager;

    /**
     * @Description：登陆系统
     * @Author：fengcheng
     * @Date：2025/1/17 10:07
     * @Param：systemUser
     * @ParamsType：[com.example.springsecurity.entity.SystemUser]
     * @Return：com.example.springsecurity.vo.UserLoginResultVo
     */
    @Override
    public UserLoginResultVo login(SystemUser systemUser) {
        UserLoginResultVo resultVO = new UserLoginResultVo();
        String mobile = systemUser.getMobile();
        try {
            // 登陆前，先通过【AuthenticationManager】进行用户身份认证
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(mobile, systemUser.getPassword());
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            if (ObjectUtils.isEmpty(authenticate) || !authenticate.isAuthenticated()) throw new BizException("用户登陆认证失败！");
            String token = jwtTokenUtil.generateToken(mobile);
            resultVO.setToken(token);
            resultVO.setRefreshToken(token);
            systemUserMapper.updateUserInfoByUserName(mobile, 0);
            //把完整的用户信息存入redis  【mobile】作为key
            //如果认证通过了，使用userid生成一个jwt jwt存入ResponseResult返回
            SystemUserLoginDetail systemUserLoginDetail = (SystemUserLoginDetail) authenticate.getPrincipal();
            redisCache.setCacheObject(REDIS_LOGIN_PATH + mobile, systemUserLoginDetail);
        } catch (Exception e) {
            systemUserMapper.updateUserInfoByUserName(mobile, 1);
            log.error("登陆失败，登陆电话号码：{}，异常信息：{}", mobile, e.getMessage(), e);
            throw new BizException("500", "登陆失败");
        }
        return resultVO;
    }

    /**
     * @Description：退出系统
     * @Author：fengcheng
     * @Date：2025/1/17 10:07
     * @Param：authorization
     * @ParamsType：[java.lang.String]
     * @Return：java.lang.Boolean
     */
    @Override
    public Boolean logout(String authorization) {
        if (StringUtils.isBlank(authorization) || !authorization.startsWith(jwtTokenUtil.getTokenHead())) {
            log.error("退出系统，身份验证失败，{}", GlobalExceptionEnum.ERROR_UNAUTHORIZED.getMessage());
            throw new BizException(GlobalExceptionEnum.ERROR_UNAUTHORIZED.getMessage());
        }
        String authToken = authorization.substring(jwtTokenUtil.getTokenHead().length());
        String mobile = jwtTokenUtil.getUserNameFromToken(authToken);
        log.info("退出系统，操作账号，{}", mobile);
        return deleteUserLoginInfo(redisCache);
    }

    /**
     * @Description：登陆时是否显示验证码
     * @Author：fengcheng
     * @Date：2025/1/17 10:16
     * @Param：mobile
     * @ParamsType：[java.lang.String]
     * @Return：boolean
     */
    @Override
    public boolean enableCaptcha(String mobile) {
        SystemUser user = systemUserMapper.selectUserInfoByUserPhone(mobile);
        if (ObjectUtil.isEmpty(user)) throw new BizException("用户不存在！");
        return user.getEnableCaptcha() >= Constant.ENABLE_CAPTCHA_NUMBER;
    }

    /**
     * @Description：获取用户信息接口
     * @Author：fengcheng
     * @Date：2025/1/17 10:17
     * @Param：authorizationHeader
     * @ParamsType：[java.lang.String]
     * @Return：com.example.springsecurity.vo.login.SystemUserLoginInfoVo
     */
    @Override
    public SystemUserLoginInfoVo getUserInfo(String authorizationHeader) {
        if (StringUtils.isBlank(authorizationHeader) || !authorizationHeader.startsWith(jwtTokenUtil.getTokenHead())) {
            log.error("获取用户登陆信息，{}", GlobalExceptionEnum.ERROR_UNAUTHORIZED.getMessage());
            throw new BizException(GlobalExceptionEnum.ERROR_UNAUTHORIZED.getMessage());
        }
        SystemUserLoginInfoVo systemUserLoginInfoVo = new SystemUserLoginInfoVo();
        try {
            String authToken = authorizationHeader.substring(jwtTokenUtil.getTokenHead().length());
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            if (username != null) {
                // 从数据库中获取用户信息
                SystemUserLoginDetail userDetails = (SystemUserLoginDetail) this.userDetailsService.loadUserByUsername(username);
                systemUserLoginInfoVo.setRoles(userDetails.getRoles());
                systemUserLoginInfoVo.setUserName(userDetails.getUsername());
                systemUserLoginInfoVo.setUserId(userDetails.getSystemUser().getId());
                return systemUserLoginInfoVo;
            }
        } catch (Exception e) {
            log.info("获取用户信息失败: {}", e.getMessage(), e);
            throw new BizException(GlobalExceptionEnum.ERROR_UNABLE_GET_USER.getMessage());
        }
        return systemUserLoginInfoVo;
    }
}
